/**
 * GWT Kad : Kademlia implementation for GWT
 * Copyright (C) 2012  Pierrick HYMBERT, Paul-André MISTRAL, Florian ALEXANDRE
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.kad.gwt.web.client.transport.http.applet;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;

import org.kad.gwt.web.client.GWTKad;
import org.kad.gwt.web.client.applet.AppletListener;
import org.kad.gwt.web.client.applet.GWTKadApplet;
import org.kad.gwt.web.client.kademelia.inject.KadModule;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * Handle the communication with the java applet throw GWT and JSNI.
 * @author Pierrick HYMBERT &lt;pierrick [dot] hymbert [at] gmail [dot] com&gt;
 */
public class GWTKadAppletClient implements GWTKadApplet {
    /**
     * The applet provider.
     */
    private final Provider<JavaScriptObject> gwtKadAppletProvider;
    /**
     * Allow the conversion of GWT <code>GWTKadAppletClient</code> to <code>GWTKadAppletListenerJSAdapter</code>.
     */
    private JavaScriptObject transformListener;
    /**
     * Constructor.
     * @param gwtKadAppletProviderIn The applet provider
     * @param context The kad server context
     * @param port The kad server listen port
     */
    @Inject
    public GWTKadAppletClient(@Named(AppletModule.APPLET) Provider<JavaScriptObject> gwtKadAppletProviderIn, @Named(KadModule.KAD_LOCAL_NODE_ID) String kadClientId) {
        this.gwtKadAppletProvider = gwtKadAppletProviderIn;
        this.enhanceByJsni();
        this.installApplet("/" + kadClientId, GWTKad.GWT_KAD_PORT_START);
    }
    /**
     * Create the {@link #transformListener}.
     */
    private native void enhanceByJsni() /*-{
        var me = this;
        this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::transformListener = function(listener) {
            var javaPackages = me.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()().Packages;
            return new javaPackages.org.kad.gwt.web.client.applet.internal.AppletListenerJSAdapter({
                handle: function(param1, param2, param3) {
                    listener.@org.kad.gwt.web.client.applet.AppletListener::handle(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(param1, param2, param3);
                },
                setCallback: function(param3) {
                    var m = listener.@org.kad.gwt.web.client.transport.http.listeners.GWTKadAppletMessageListener::setCallBack;
                    m(param3);
                }
            });
        }
    }-*/;

    /**
     * Install the gwt kad applet.
     */
    private native void installApplet(String context, int port) /*-{
        var attributes = {
                id: @org.kad.gwt.web.client.transport.http.applet.AppletModule::APPLET,
                name: @org.kad.gwt.web.client.transport.http.applet.AppletModule::APPLET,
                code:'org.kad.gwt.web.client.applet.internal.GWTKadAppletImpl',
                width:1,
                height:1,
                mayscript:true
         };
        var parameters = {
            jnlp_href: 'jnlp/launch.jnlp',
            separate_jvm:true,
            classloader_cache:false
        };
        parameters[@org.kad.gwt.web.client.applet.GWTKadApplet::APPLET_CONTEXT] = context;
        parameters[@org.kad.gwt.web.client.applet.GWTKadApplet::APPLET_PORT] = port;
        var applet = $wnd.document.createElement("applet");
        for (attibute in attributes) {
            applet.setAttribute(attibute, attributes[attibute]);
        }
        for (param in parameters) {
            var paramTag = $wnd.document.createElement("param");
            paramTag.setAttribute("name", param);
            paramTag.setAttribute("value", parameters[param]);
            applet.appendChild(paramTag);
        }
        $wnd.document.body.appendChild(applet);
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native void addErrorListener(AppletListener errorListener) /*-{
        this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()()
            .addErrorListener(this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::getTransformListener()()(errorListener));
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native void addMessageListener(AppletListener messageListener) /*-{
        this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()()
            .addMessageListener(this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::getTransformListener()()(messageListener));
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native void removeMessageListener(AppletListener messageListener) /*-{
        this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()()
            .removeMessageListener(this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::getTransformListener()()(messageListener));
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native void removeErrorListener(AppletListener errorListener) /*-{
        this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()()
            .removeErrorListener(this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::getTransformListener()()(errorListener));
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native int getListenPort() /*-{
        return this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()()
            .getListenPort();
    }-*/;

    /**
     * {@inheritDoc}
     */
    @Override
    public native boolean isReady() /*-{
        var ready = false;
        try {
            ready = this.@org.kad.gwt.web.client.transport.http.applet.GWTKadAppletClient::gwtKadAppletProvider.@javax.inject.Provider::get()().isReady();
        } catch (e) {}
        return ready;
    }-*/;

    /**
     * @return The listener adapter transformer.
     */
    private JavaScriptObject getTransformListener() {
        return transformListener;
    }
}
